package com.cq.hd.member.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cq.hd.common.constant.Constant;
import com.cq.hd.common.constant.MsgConstant;
import com.cq.hd.common.entity.hf.HfSettlement;
import com.cq.hd.common.entity.mq.NotifyMsgSendDto;
import com.cq.hd.common.enums.biz.*;
import com.cq.hd.common.exception.BusinessException;
import com.cq.hd.common.pagination.Page;
import com.cq.hd.common.response.Throw;
import com.cq.hd.common.utils.BeanUtils;
import com.cq.hd.common.utils.NoUtils;
import com.cq.hd.common.utils.StringUtils;
import com.cq.hd.member.api.dto.*;
import com.cq.hd.member.api.vo.*;
import com.cq.hd.member.config.LockUtils;
import com.cq.hd.member.factory.WithdrawalFactory;
import com.cq.hd.member.mapper.*;
import com.cq.hd.member.mq.provider.NotifyMsgProvider;
import com.cq.hd.member.mq.provider.WithdrawalMsgProvider;
import com.cq.hd.member.po.*;
import com.cq.hd.member.service.*;
import com.cq.hd.order.api.TbMonthSettleBillApi;
import com.cq.hd.order.api.TbOrderSettleBillApi;
import com.cq.hd.order.api.dto.OrderSettleBillDto;
import com.cq.hd.order.api.vo.OrderSettleBillVo;
import com.cq.hd.system.api.HfApi;
import com.cq.hd.system.api.TbWithdrawalConfigApi;
import com.cq.hd.system.api.vo.WithdrawalConfigVo;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.MessageFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 提现记录表 服务实现类
 * </p>
 *
 * @author mYunYu
 * @since 2024-01-28
 */
@Service
@Slf4j
public class TbWithdrawalBillServiceImpl extends ServiceImpl<TbWithdrawalBillMapper, TbWithdrawalBillPo> implements TbWithdrawalBillService {

    @Autowired
    private TbWithdrawalConfigApi withdrawalConfigApi;

    @Autowired
    private TbAppUserMapper appUserMapper;

    @Autowired
    private TbMerchantMapper merchantMapper;

    @Autowired
    private TbCommissionBillMapper commissionBillMapper;

    @Autowired
    private PlatformTransactionManager transactionManager;

    @Autowired
    private WithdrawalMsgProvider withdrawalMsgProvider;

    @Autowired
    private TbMerchantAmtBillMapper merchantAmtBillMapper;

    @Autowired
    private HfApi hfApi;

    @Autowired
    private NotifyMsgProvider notifyMsgProvider;

    @Autowired
    private TbOrderSettleBillApi orderSettleBillApi;

    @Autowired
    private TbBusinessMapper businessMapper;

    @Autowired
    private TbMerchantService merchantService;

    @Autowired
    private TbWithdrawalCheckBillService withdrawalCheckBillService;

    @Autowired
    private TbWithdrawalBillPaymentVoucherService withdrawalBillPaymentVoucherService;

    @Autowired
    private AutoWithdrawalResultService autoWithdrawalResultService;

    @Resource
    protected TbMonthSettleBillApi monthSettleBillApi;

    @Override
    public Boolean apply(WithdrawalApplyDto withdrawalApplyDto) {
        // 提现类型(1-商户本金提现，2-佣金提现，3-商户补贴提现)
        Integer withdrawalType = withdrawalApplyDto.getWithdrawalType();
        if (withdrawalType == null || WithdrawalConfigUserTypeEnum.typeOf(withdrawalType) == null) {
            Throw.isBusinessException("请选择申请提现类型");
        }

        // 对用户id加锁
        String lockKey = MessageFormat.format(Constant.LOCK_FORMAT, "withdrawalApply:" + withdrawalType + "-" + withdrawalApplyDto.getUserId());
        try {
            LockUtils.blockLock(lockKey, Constant.AUTO_UNLOCK_SECOND);

            WithdrawalConfigVo withdrawalConfigVo = withdrawalConfigApi.details(withdrawalType, withdrawalApplyDto.getFinancialAccountType()).unpack();
            if (withdrawalConfigVo == null) {
                log.error("申请提现失败，未配置提现参数，withdrawalType：{}", withdrawalType);
                Throw.isBusinessException("申请提现失败，请联系客服");
            }

            return WithdrawalFactory.getWithdrawalHandler(withdrawalType).apply(withdrawalApplyDto, withdrawalConfigVo);
        } finally {
            LockUtils.unlock(lockKey);
        }
    }

    /**
     * 商户申请本金，补贴提现
     * 佣金提现目前没有用到
     */
    @Override
    public Boolean applyV2(WithdrawalApplyV2Dto withdrawalApplyV2Dto) {
        // 提现类型(1-商户本金提现，2-佣金提现，3-商户补贴提现)
        Integer withdrawalType = withdrawalApplyV2Dto.getWithdrawalType();
        if (withdrawalType == null || WithdrawalConfigUserTypeEnum.typeOf(withdrawalType) == null) {
            Throw.isBusinessException("请选择申请提现类型");
        }

        // 对用户id加锁
        String lockKey = MessageFormat.format(Constant.LOCK_FORMAT, "withdrawalApplyV2:" + withdrawalType + "-" + withdrawalApplyV2Dto.getUserId());
        try {
            LockUtils.blockLock(lockKey, Constant.AUTO_UNLOCK_SECOND);

            WithdrawalConfigVo withdrawalConfigVo = withdrawalConfigApi.details(withdrawalType, withdrawalApplyV2Dto.getFinancialAccountType()).unpack();
            if (withdrawalConfigVo == null) {
                log.error("申请提现失败，未配置提现参数，withdrawalType：{}", withdrawalType);
                Throw.isBusinessException("申请提现失败，请联系客服");
            }

            return WithdrawalFactory.getWithdrawalHandler(withdrawalType).applyV2(withdrawalApplyV2Dto, withdrawalConfigVo);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new BusinessException(e.getMessage());
        } finally {
            LockUtils.unlock(lockKey);
        }
    }

    @Override
    public Page<WithdrawalApplyPageVo> pageWithdrawalBill(WithdrawalApplyPageDto withdrawalApplyPageDto) {
        PageHelper.startPage(withdrawalApplyPageDto.getPageNum(), withdrawalApplyPageDto.getPageSize());
        List<WithdrawalApplyPageVo> withdrawalApplyPageVos = baseMapper.listAppWithdrawalBillByDto(withdrawalApplyPageDto);
        PageInfo<WithdrawalApplyPageVo> pageInfo = new PageInfo<>(withdrawalApplyPageVos);
        return Page.newPageWithAllFields(pageInfo.getList(), pageInfo.getPageNum(), pageInfo.getPageSize(), pageInfo.getTotal(), pageInfo.getPages());
    }

    @Override
    public Page<WithdrawalApplyPageVo> pageMerchantWithdrawalBill(WithdrawalApplyPageDto withdrawalApplyPageDto) {
        MerchantVo merchantVo = merchantService.getMerchantById(withdrawalApplyPageDto.getUserId());
        setWithdrawalTypeScope(withdrawalApplyPageDto, merchantVo);
        PageHelper.startPage(withdrawalApplyPageDto.getPageNum(), withdrawalApplyPageDto.getPageSize());
        List<WithdrawalApplyPageVo> withdrawalApplyPageVos = baseMapper.listAppWithdrawalBillByDto(withdrawalApplyPageDto);
        PageInfo<WithdrawalApplyPageVo> pageInfo = new PageInfo<>(withdrawalApplyPageVos);
        // 设置核算单信息
        setCheckBillInfo(pageInfo);
        return Page.newPageWithAllFields(pageInfo.getList(), pageInfo.getPageNum(), pageInfo.getPageSize(), pageInfo.getTotal(), pageInfo.getPages());
    }

    private void setWithdrawalTypeScope(WithdrawalApplyPageDto withdrawalApplyPageDto, MerchantVo merchantVo) {
        if (FinancialAccountTypeEnum.SELF.getValue() == merchantVo.getFinancialAccountType()
                && !CollectionUtils.isEmpty(withdrawalApplyPageDto.getWithdrawalTypes())
                && withdrawalApplyPageDto.getWithdrawalTypes().contains(WithdrawalTypeEnum.MERCHANT_AMT.getValue())) {
            // 如果是普通商户本金提现，自动提现记录也要展示
            withdrawalApplyPageDto.getWithdrawalTypes().add(WithdrawalTypeEnum.MERCHANT_AUTO_AMT.getValue());
        }

//        if (FinancialAccountTypeEnum.SELF.getValue() == merchantVo.getFinancialAccountType()) {
//            withdrawalApplyPageDto.setWithdrawalTypeScopes(Collections.singletonList(WithdrawalTypeEnum.MERCHANT_SUBSIDY.getValue()));
//        } else if(FinancialAccountTypeEnum.PLATFORM.getValue() == merchantVo.getFinancialAccountType()) {
//            withdrawalApplyPageDto.setWithdrawalTypeScopes(Arrays.asList(WithdrawalTypeEnum.MERCHANT_AMT.getValue(), WithdrawalTypeEnum.MERCHANT_SUBSIDY.getValue()));
//        }
    }

    /**
     * 设置核算单信息
     */
    private void setCheckBillInfo(PageInfo<WithdrawalApplyPageVo> pageInfo) {
       if (CollectionUtils.isEmpty(pageInfo.getList())) {
           return;
       }
        List<Long> withdrawalIds = pageInfo.getList().stream().map(WithdrawalApplyPageVo::getId).collect(Collectors.toList());
        List<WithdrawalCheckBillVo> withdrawalCheckBillVos = withdrawalCheckBillService.listByWithdrawalBillIds(withdrawalIds);
        if (CollectionUtils.isEmpty(withdrawalCheckBillVos)) {
            return;
        }
        Map<Long, WithdrawalCheckBillVo> withdrawalIdToCheckBill = withdrawalCheckBillVos.stream()
                .collect(Collectors.toMap(WithdrawalCheckBillVo::getWithdrawalBillId, Function.identity()));
        for (WithdrawalApplyPageVo pageVo : pageInfo.getList()) {
            WithdrawalCheckBillVo withdrawalCheckBillVo = withdrawalIdToCheckBill.get(pageVo.getId());
            if (withdrawalCheckBillVo != null) {
                pageVo.setCheckBillId(withdrawalCheckBillVo.getId());
                pageVo.setCheckStatus(withdrawalCheckBillVo.getStatus());
                pageVo.setCheckFile(withdrawalCheckBillVo.getCheckFile());
            }
        }
    }

    @Override
    public Page<AdminWithdrawalApplyPageVo> pageAdminWithdrawalBill(AdminWithdrawalApplyPageDto adminWithdrawalApplyPageDto) {
        Integer withdrawalType = adminWithdrawalApplyPageDto.getWithdrawalType();
        if (WithdrawalTypeEnum.AGENT_COMMISSION.getValue().equals(withdrawalType)) {
            PageHelper.startPage(adminWithdrawalApplyPageDto.getPageNum(), adminWithdrawalApplyPageDto.getPageSize());
            List<AdminWithdrawalApplyPageVo> withdrawalApplyPageVos = baseMapper.listAdminAgentWithdrawalBillByDto(adminWithdrawalApplyPageDto);
            PageInfo<AdminWithdrawalApplyPageVo> pageInfo = new PageInfo<>(withdrawalApplyPageVos);
            return Page.newPageWithAllFields(pageInfo.getList(), pageInfo.getPageNum(), pageInfo.getPageSize(), pageInfo.getTotal(), pageInfo.getPages());
        } else if (WithdrawalTypeEnum.MERCHANT_AMT.getValue().equals(withdrawalType) || WithdrawalTypeEnum.MERCHANT_SUBSIDY.getValue().equals(withdrawalType)) {
            PageHelper.startPage(adminWithdrawalApplyPageDto.getPageNum(), adminWithdrawalApplyPageDto.getPageSize());
            List<AdminWithdrawalApplyPageVo> withdrawalApplyPageVos = baseMapper.listAdminMerchantWithdrawalBillByDto(adminWithdrawalApplyPageDto);
            PageInfo<AdminWithdrawalApplyPageVo> pageInfo = new PageInfo<>(withdrawalApplyPageVos);
            return Page.newPageWithAllFields(pageInfo.getList(), pageInfo.getPageNum(), pageInfo.getPageSize(), pageInfo.getTotal(), pageInfo.getPages());
        }

        return null;
    }

    @Override
    public Boolean audit(AdminWithdrawalApplyAuditDto adminWithdrawalApplyAuditDto) {
        Long id = adminWithdrawalApplyAuditDto.getId();
        if (id == null || id <= 0) {
            Throw.isBusinessException("请选择审核的提现记录");
        }

        Integer auditState = adminWithdrawalApplyAuditDto.getAuditState();
        if (auditState == null) {
            Throw.isBusinessException("请选择审核状态");
        }

        if (WithdrawalStateEnum.typeOf(auditState) == null) {
            Throw.isBusinessException("审核状态错误");
        }

        TbWithdrawalBillPo tbWithdrawalBillPo = baseMapper.selectById(id);
        if (tbWithdrawalBillPo == null || tbWithdrawalBillPo.getDelState() != 0) {
            Throw.isBusinessException("提现记录不存在");
        }

        if (!WithdrawalStateEnum.WAIT_AUDIT.getValue().equals(tbWithdrawalBillPo.getState())) {
            Throw.isBusinessException("提现记录已审核");
        }

        Long withdrawalUserId = tbWithdrawalBillPo.getWithdrawalUserId();
        BigDecimal tradeAmt = tbWithdrawalBillPo.getTradeAmt();

        // 根据提现类型,获取对应的账户余额
        BigDecimal beforeAmt = getBeforeAmt(tbWithdrawalBillPo, withdrawalUserId);

        TransactionStatus transaction = transactionManager.getTransaction(new DefaultTransactionAttribute());

        try {
            // 修改提现记录状态
            if (WithdrawalStateEnum.AUDIT_FAIL.getValue().equals(auditState)) {
                tbWithdrawalBillPo.setRefuseReason(adminWithdrawalApplyAuditDto.getRefuseReason());
            }
            tbWithdrawalBillPo.setState(auditState);
            tbWithdrawalBillPo.setAuditTime(LocalDateTime.now());
            tbWithdrawalBillPo.setUpdateTime(LocalDateTime.now());
            int update = baseMapper.updateById(tbWithdrawalBillPo);
            if (update <= 0) {
                log.error("提现审核失败，id：{}", id);
                Throw.isBusinessException("审核失败");
            }

            if (WithdrawalStateEnum.AUDIT_FAIL.getValue().equals(auditState)) {
                // 审核拒绝，提现资金退回

                if (WithdrawalTypeEnum.MERCHANT_AMT.getValue().equals(tbWithdrawalBillPo.getWithdrawalType())) {
                    // 增加商户本金账户资金明细记录
                    TbMerchantAmtBillPo tbMerchantAmtBillPo = new TbMerchantAmtBillPo();
                    tbMerchantAmtBillPo.setBillNo(NoUtils.getMerchantAmtBillNo());
                    tbMerchantAmtBillPo.setMerchantId(tbWithdrawalBillPo.getWithdrawalUserId());
                    tbMerchantAmtBillPo.setBillType(BillTypeEnum.INCOME.getValue());
                    tbMerchantAmtBillPo.setTradeType(MemberAmtBillTradeTypeEnum.WITHDRAWAL_AMT_FAIL.getValue());
                    tbMerchantAmtBillPo.setRelationTradeNo(tbWithdrawalBillPo.getApplyNo());
                    tbMerchantAmtBillPo.setBeforeAmt(beforeAmt);
                    tbMerchantAmtBillPo.setTradeAmt(tradeAmt);
                    tbMerchantAmtBillPo.setRemark(tbWithdrawalBillPo.getRemark());
                    tbMerchantAmtBillPo.setAfterAmt(beforeAmt.add(tradeAmt));
                    tbMerchantAmtBillPo.setTradeTime(tbWithdrawalBillPo.getApplyTime());
                    tbMerchantAmtBillPo.setCreateTime(LocalDateTime.now());
                    tbMerchantAmtBillPo.setUpdateTime(LocalDateTime.now());
                    int insert = merchantAmtBillMapper.insert(tbMerchantAmtBillPo);
                    if (insert == 0) {
                        log.error("提现审核失败，添加商户资金流水失败，id：{}", id);
                        Throw.isBusinessException("审核失败");
                    }

                    // 退回商户本金
                    MerchantAmtAddDto merchantAmtAddDto = new MerchantAmtAddDto();
                    merchantAmtAddDto.setId(withdrawalUserId);
                    merchantAmtAddDto.setBalanceAmt(tradeAmt);
                    Boolean merchantAmtAddState = merchantMapper.merchantAmtAddDto(merchantAmtAddDto);
                    if (merchantAmtAddState == null || !merchantAmtAddState) {
                        log.error("提现审核失败，退回商户本金失败，id：{}", id);
                        Throw.isBusinessException("审核失败");
                    }
                } else if (WithdrawalTypeEnum.MERCHANT_SUBSIDY.getValue().equals(tbWithdrawalBillPo.getWithdrawalType())) {
                    // 增加商户补贴账户资金明细记录
                    TbMerchantAmtBillPo tbMerchantAmtBillPo = new TbMerchantAmtBillPo();
                    tbMerchantAmtBillPo.setBillNo(NoUtils.getMerchantAmtBillNo());
                    tbMerchantAmtBillPo.setMerchantId(tbWithdrawalBillPo.getWithdrawalUserId());
                    tbMerchantAmtBillPo.setBillType(BillTypeEnum.INCOME.getValue());
                    tbMerchantAmtBillPo.setTradeType(MemberAmtBillTradeTypeEnum.WITHDRAWAL_SUBSIDY_FAIL.getValue());
                    tbMerchantAmtBillPo.setRelationTradeNo(tbWithdrawalBillPo.getApplyNo());
                    tbMerchantAmtBillPo.setBeforeAmt(beforeAmt);
                    tbMerchantAmtBillPo.setTradeAmt(tradeAmt);
                    tbMerchantAmtBillPo.setAfterAmt(beforeAmt.add(tradeAmt));
                    tbMerchantAmtBillPo.setRemark(tbWithdrawalBillPo.getRemark());
                    tbMerchantAmtBillPo.setTradeTime(tbWithdrawalBillPo.getApplyTime());
                    tbMerchantAmtBillPo.setCreateTime(LocalDateTime.now());
                    tbMerchantAmtBillPo.setUpdateTime(LocalDateTime.now());
                    int insert = merchantAmtBillMapper.insert(tbMerchantAmtBillPo);
                    if (insert == 0) {
                        log.error("提现审核失败，添加商户资金流水失败，id：{}", id);
                        Throw.isBusinessException("审核失败");
                    }

                    // 退回商户补贴
                    MerchantAmtAddDto merchantAmtAddDto = new MerchantAmtAddDto();
                    merchantAmtAddDto.setId(withdrawalUserId);
                    merchantAmtAddDto.setSubsidyAmt(tradeAmt);
                    Boolean merchantAmtAddState = merchantMapper.merchantAmtAddDto(merchantAmtAddDto);
                    if (merchantAmtAddState == null || !merchantAmtAddState) {
                        log.error("提现审核失败，退回商户补贴失败，id：{}", id);
                        Throw.isBusinessException("审核失败");
                    }
                } else if (WithdrawalTypeEnum.AGENT_COMMISSION.getValue().equals(tbWithdrawalBillPo.getWithdrawalType())) {
                    // 增加佣金账户资金明细记录
                    TbCommissionBillPo tbCommissionBillPo = new TbCommissionBillPo();
                    tbCommissionBillPo.setBillNo(NoUtils.getCommissionBillNo());
                    tbCommissionBillPo.setUserId(tbWithdrawalBillPo.getWithdrawalUserId());
                    tbCommissionBillPo.setBillType(BillTypeEnum.INCOME.getValue());
                    tbCommissionBillPo.setTradeType(CommissionBillTradeTypeEnum.WITHDRAWAL_COMMISSION_FAIL.getValue());
                    tbCommissionBillPo.setRelationTradeNo(tbWithdrawalBillPo.getApplyNo());
                    tbCommissionBillPo.setBeforeAmt(beforeAmt);
                    tbCommissionBillPo.setTradeAmt(tradeAmt);
                    tbCommissionBillPo.setAfterAmt(beforeAmt.add(tradeAmt));
                    tbCommissionBillPo.setTradeTime(tbWithdrawalBillPo.getAuditTime());
                    tbCommissionBillPo.setCreateTime(LocalDateTime.now());
                    tbCommissionBillPo.setUpdateTime(LocalDateTime.now());
                    int insert = commissionBillMapper.insert(tbCommissionBillPo);
                    if (insert == 0) {
                        log.error("提现审核失败，添加佣金流水失败，id：{}", id);
                        Throw.isBusinessException("审核失败");
                    }

                    // 退回经纪人佣金
                    Boolean addCommissionAmtState = appUserMapper.addCommissionAmt(withdrawalUserId, tradeAmt);
                    if (addCommissionAmtState == null || !addCommissionAmtState) {
                        log.error("提现审核失败，退回经纪人佣金失败，id：{}", id);
                        Throw.isBusinessException("审核失败");
                    }
                }
            }

            // 补贴，本金提现审核，更新相关联的月度结算单状态
            if (!Objects.equals(WithdrawalTypeEnum.AGENT_COMMISSION.getValue(), tbWithdrawalBillPo.getWithdrawalType())) {
                boolean success = monthSettleBillApi.withdrawalUpdateStatus(id, auditState).unpack();
                if (!success) {
                    log.error("提现审核失败，修改月度结算单状态失败 id: {}, auditState: {}", id, auditState);
                    Throw.isBusinessException("提现审核失败。请稍后重试");
                }
            }

            transactionManager.commit(transaction);
        } catch (Exception e) {
            //回滚事务
            transactionManager.rollback(transaction);
            log.error("<提现审核失败>事务异常回滚", e);
            Throw.isBusinessException(e.getMessage());
        }

        if (WithdrawalStateEnum.AUDIT_SUCCESS.getValue().equals(auditState)) {
            // 审核成功， 发送mq消息做异步打款操作
            withdrawalMsgProvider.sendMsg(tbWithdrawalBillPo.getId());

            // 发送提现审核结果系统通知
            NotifyMsgSendDto notifyMsgSendDto = new NotifyMsgSendDto();
            notifyMsgSendDto.setUserId(tbWithdrawalBillPo.getWithdrawalUserId());
            notifyMsgSendDto.setMsgState(NotifyMsgStateEnum.NO_READ.getValue());
            if (WithdrawalTypeEnum.AGENT_COMMISSION.getValue().equals(tbWithdrawalBillPo.getWithdrawalType())) {
                notifyMsgSendDto.setRoleType(RoleTypeEnum.BUSINESS.getValue());
                notifyMsgSendDto.setMsgType(NotifyMsgTypeEnum.AGENT_WITHDRAWAL_AUDIT.getValue());
                notifyMsgSendDto.setContent(String.format(MsgConstant.AGENT_WITHDRAWAL_AUDIT_SUCCESS,
                        tbWithdrawalBillPo.getTradeAmt(),
                        tbWithdrawalBillPo.getApplyNo()));
            }
//            else if (WithdrawalTypeEnum.MERCHANT_AMT.getValue().equals(tbWithdrawalBillPo.getWithdrawalType())
//                    || WithdrawalTypeEnum.MERCHANT_SUBSIDY.getValue().equals(tbWithdrawalBillPo.getWithdrawalType())) {
//                // 您申请的%s提现金额已到账，请至收款账户查收确认。
//                notifyMsgSendDto.setRoleType(RoleTypeEnum.MERCHANT.getValue());
//                notifyMsgSendDto.setMsgType(NotifyMsgTypeEnum.MERCHANT_WITHDRAWAL_SUCCESS.getValue());
//                notifyMsgSendDto.setContent(String.format(MsgConstant.MERCHANT_WITHDRAWAL_SUCCESS,
//                        tbWithdrawalBillPo.getTradeAmt()));
//            }

            notifyMsgProvider.sendMsg(notifyMsgSendDto);
        }

        // 审核失败,发送系统通知, 审核不通过：您申请的%s元提现（提现单号：%s）审核未通过，原因：%s
        if (WithdrawalStateEnum.AUDIT_FAIL.getValue().equals(auditState)) {
            NotifyMsgSendDto notifyMsgSendDto = new NotifyMsgSendDto();
            notifyMsgSendDto.setUserId(tbWithdrawalBillPo.getWithdrawalUserId());
            notifyMsgSendDto.setMsgState(NotifyMsgStateEnum.NO_READ.getValue());

            if (WithdrawalTypeEnum.AGENT_COMMISSION.getValue().equals(tbWithdrawalBillPo.getWithdrawalType())) {
                // 发送提现审核结果系统通知
                notifyMsgSendDto.setRoleType(RoleTypeEnum.BUSINESS.getValue());
                notifyMsgSendDto.setMsgType(NotifyMsgTypeEnum.AGENT_WITHDRAWAL_AUDIT.getValue());
                notifyMsgSendDto.setContent(String.format(MsgConstant.AGENT_WITHDRAWAL_AUDIT_FAIL,
                        tbWithdrawalBillPo.getTradeAmt(),
                        tbWithdrawalBillPo.getApplyNo(),
                        tbWithdrawalBillPo.getRefuseReason()));
            }
            else if (WithdrawalTypeEnum.MERCHANT_AMT.getValue().equals(tbWithdrawalBillPo.getWithdrawalType())
                    || WithdrawalTypeEnum.MERCHANT_SUBSIDY.getValue().equals(tbWithdrawalBillPo.getWithdrawalType())) {
                // 发送提现失败系统通知
                notifyMsgSendDto.setRoleType(RoleTypeEnum.MERCHANT.getValue());
                notifyMsgSendDto.setMsgType(NotifyMsgTypeEnum.MERCHANT_WITHDRAWAL_FAIL.getValue());
                notifyMsgSendDto.setContent(String.format(MsgConstant.MERCHANT_WITHDRAWAL_FAIL,
                        tbWithdrawalBillPo.getTradeAmt(), tbWithdrawalBillPo.getRefuseReason()));
            }

            notifyMsgProvider.sendMsg(notifyMsgSendDto);
        }

        return true;
    }

    @Override
    public AdminWithdrawalAmtVo getWithdrawalAmt(AdminWithdrawalApplyPageDto adminWithdrawalApplyPageDto) {
        // 累计申请金额=所有提现记录总和，不管状态
        BigDecimal totalApplyAmt = BigDecimal.ZERO;
        // 累计已提现金额=提现成功的提现金额
        BigDecimal totalSuccessAmt = BigDecimal.ZERO;

        List<AdminWithdrawalApplyPageVo> withdrawalApplyPageVos = new ArrayList<>();

        Integer withdrawalType = adminWithdrawalApplyPageDto.getWithdrawalType();
        if (WithdrawalTypeEnum.AGENT_COMMISSION.getValue().equals(withdrawalType)) {
            withdrawalApplyPageVos = baseMapper.listAdminAgentWithdrawalBillByDto(adminWithdrawalApplyPageDto);
        } else if (WithdrawalTypeEnum.MERCHANT_AMT.getValue().equals(withdrawalType) || WithdrawalTypeEnum.MERCHANT_SUBSIDY.getValue().equals(withdrawalType)) {
            withdrawalApplyPageVos = baseMapper.listAdminMerchantWithdrawalBillByDto(adminWithdrawalApplyPageDto);
        }

        if (!CollectionUtils.isEmpty(withdrawalApplyPageVos)) {
            for (AdminWithdrawalApplyPageVo withdrawalApplyPageVo : withdrawalApplyPageVos) {
                BigDecimal tradeAmt = withdrawalApplyPageVo.getTradeAmt();
                Integer state = withdrawalApplyPageVo.getState();

                if (WithdrawalStateEnum.WITHDRAWAL_SUCCESS.getValue().equals(state)) {
                    totalSuccessAmt = totalSuccessAmt.add(tradeAmt);
                }
                totalApplyAmt = totalApplyAmt.add(tradeAmt);
            }
        }

        AdminWithdrawalAmtVo adminWithdrawalAmtVo = new AdminWithdrawalAmtVo();
        adminWithdrawalAmtVo.setTotalApplyAmt(totalApplyAmt);
        adminWithdrawalAmtVo.setTotalSuccessAmt(totalSuccessAmt);
        return adminWithdrawalAmtVo;
    }

    @Override
    public Boolean consumerWithdrawalMsg(Long id) {
        TbWithdrawalBillPo tbWithdrawalBillPo = baseMapper.selectById(id);
        if (tbWithdrawalBillPo == null || tbWithdrawalBillPo.getDelState() != 0) {
            log.error("消费提现打款消息,未找到提现记录数据，id：{}", id);
            Throw.isBusinessException("未找到提现记录数据");
        }

        Integer withdrawalType = tbWithdrawalBillPo.getWithdrawalType();
        Long withdrawalUserId = tbWithdrawalBillPo.getWithdrawalUserId();
        BigDecimal tradeAmt = tbWithdrawalBillPo.getTradeAmt();
        String hfId = tbWithdrawalBillPo.getHfId();
        String acctId = tbWithdrawalBillPo.getAcctId();
        String tokenNo = tbWithdrawalBillPo.getTokenNo();
        BigDecimal receiveAmt = tbWithdrawalBillPo.getReceiveAmt();
        String reqDate = tbWithdrawalBillPo.getReqDate();
        String reqSeqId = tbWithdrawalBillPo.getReqSeqId();

        // 调用第三方支付接口打款，更新为提现中
        HfSettlement hfSettlement = new HfSettlement();
        hfSettlement.setHfId(hfId);
        hfSettlement.setActId(acctId);
        hfSettlement.setTokenNo(tokenNo);
        hfSettlement.setReqDate(reqDate);
        hfSettlement.setReqSeqId(reqSeqId);
        hfSettlement.setCashAmt(receiveAmt.toString());
        JSONObject jsonObject = hfApi.settlement(hfSettlement).unpack();
        if (jsonObject != null) {
            JSONObject dataJSONObject = jsonObject.getJSONObject("data");
            String transStat = dataJSONObject.getString("trans_stat");
            if ("S".equals(transStat)) {
                // 提现成功
                tbWithdrawalBillPo.setState(WithdrawalStateEnum.WITHDRAWAL_SUCCESS.getValue());
                tbWithdrawalBillPo.setArriveTime(LocalDateTime.now());
                int update = baseMapper.updateById(tbWithdrawalBillPo);
                if (update == 0) {
                    log.error("消费提现打款消息,更新提现状态失败，id：{}", id);
                    Throw.isBusinessException("更新提现状态失败");
                }

                // 发送提现到账系统通知
                // 发送系统通知,审核通过：您申请的%s元提现（提现单号：%s）已审核通过，提现金额将在3个工作日内打款至您绑定的银行卡内，节假日顺延。
                NotifyMsgSendDto notifyMsgSendDto = new NotifyMsgSendDto();
                notifyMsgSendDto.setUserId(tbWithdrawalBillPo.getWithdrawalUserId());
                notifyMsgSendDto.setMsgState(NotifyMsgStateEnum.NO_READ.getValue());
                if (WithdrawalTypeEnum.AGENT_COMMISSION.getValue().equals(tbWithdrawalBillPo.getWithdrawalType())) {
//                    notifyMsgSendDto.setRoleType(RoleTypeEnum.BUSINESS.getValue());
//                    notifyMsgSendDto.setMsgType(NotifyMsgTypeEnum.AGENT_WITHDRAWAL_AUDIT.getValue());
//                    notifyMsgSendDto.setContent(String.format(MsgConstant.AGENT_WITHDRAWAL_AUDIT_SUCCESS,
//                            tbWithdrawalBillPo.getTradeAmt(),
//                            tbWithdrawalBillPo.getApplyNo()));
                } else if (WithdrawalTypeEnum.MERCHANT_AMT.getValue().equals(tbWithdrawalBillPo.getWithdrawalType())
                        || WithdrawalTypeEnum.MERCHANT_SUBSIDY.getValue().equals(tbWithdrawalBillPo.getWithdrawalType())) {
                    // 发送提现到账系统通知
                    notifyMsgSendDto.setRoleType(RoleTypeEnum.MERCHANT.getValue());
                    notifyMsgSendDto.setMsgType(NotifyMsgTypeEnum.MERCHANT_WITHDRAWAL_SUCCESS.getValue());
                    notifyMsgSendDto.setContent(String.format(MsgConstant.MERCHANT_WITHDRAWAL_SUCCESS,
                            tbWithdrawalBillPo.getTradeAmt()));
                }

                notifyMsgProvider.sendMsg(notifyMsgSendDto);
            } else if ("F".equals(transStat)) {
                // 提现交易失败,修改提现记录状态,退还提现金额,增加资金流水,发送系统通知

                // 如果是商户补贴提现,需要查询待支付/支付失败的商户补贴类型的订单结算支付流水记录, 返回第一个商家名称作为提现失败原因
                // 如果不存在,表示可能是其他原因,则提现失败原因=提现失败,请联系客服
                String failReason = "提现失败,请联系客服";
                if (WithdrawalTypeEnum.MERCHANT_SUBSIDY.getValue().equals(withdrawalType)) {
                    OrderSettleBillDto orderSettleBillDto = new OrderSettleBillDto();
                    orderSettleBillDto.setTradeType(OrderSettleBillTradeTypeEnum.SUBSIDY_AMT.getValue());
                    orderSettleBillDto.setMerchantId(tbWithdrawalBillPo.getWithdrawalUserId());
                    orderSettleBillDto.setTradeStates(Arrays.asList(OrderSettleBillTradeStateEnum.FAIL.getValue(), OrderSettleBillTradeStateEnum.WAIT.getValue()));
                    List<OrderSettleBillVo> orderSettleBillVos = orderSettleBillApi.listByDto(orderSettleBillDto).unpack();
                    if (!CollectionUtils.isEmpty(orderSettleBillVos)) {
                        OrderSettleBillVo orderSettleBillVo = orderSettleBillVos.get(0);
                        TbBusinessPo businessPo = businessMapper.selectById(orderSettleBillVo.getBusinessId());
                        failReason = String.format("策划人【%s】账户余额不足", businessPo.getBusinessShortName());
                    }
                }

                // 根据提现类型,获取对应的账户余额
                BigDecimal beforeAmt = getBeforeAmt(tbWithdrawalBillPo, withdrawalUserId);

                TransactionStatus transaction = transactionManager.getTransaction(new DefaultTransactionAttribute());

                try {
                    tbWithdrawalBillPo.setState(WithdrawalStateEnum.WITHDRAWAL_FAIL.getValue());
                    tbWithdrawalBillPo.setUpdateTime(LocalDateTime.now());
                    tbWithdrawalBillPo.setHfFailReason(JSON.toJSONString(dataJSONObject));
                    int update = baseMapper.updateById(tbWithdrawalBillPo);
                    if (update == 0) {
                        log.error("消费提现打款消息，更新提现状态失败，id：{}", id);
                        Throw.isBusinessException("更新提现状态失败");
                    }

                    if (WithdrawalTypeEnum.MERCHANT_AMT.getValue().equals(withdrawalType)) {
                        // 增加商户本金账户资金明细记录
                        TbMerchantAmtBillPo tbMerchantAmtBillPo = new TbMerchantAmtBillPo();
                        tbMerchantAmtBillPo.setBillNo(NoUtils.getMerchantAmtBillNo());
                        tbMerchantAmtBillPo.setMerchantId(tbWithdrawalBillPo.getWithdrawalUserId());
                        tbMerchantAmtBillPo.setBillType(BillTypeEnum.INCOME.getValue());
                        tbMerchantAmtBillPo.setTradeType(MemberAmtBillTradeTypeEnum.WITHDRAWAL_AMT_FAIL.getValue());
                        tbMerchantAmtBillPo.setRelationTradeNo(tbWithdrawalBillPo.getApplyNo());
                        tbMerchantAmtBillPo.setBeforeAmt(beforeAmt);
                        tbMerchantAmtBillPo.setTradeAmt(tradeAmt);
                        tbMerchantAmtBillPo.setAfterAmt(beforeAmt.add(tradeAmt));
                        tbMerchantAmtBillPo.setRemark(tbWithdrawalBillPo.getRemark());
                        tbMerchantAmtBillPo.setTradeTime(tbWithdrawalBillPo.getApplyTime());
                        tbMerchantAmtBillPo.setCreateTime(LocalDateTime.now());
                        tbMerchantAmtBillPo.setUpdateTime(LocalDateTime.now());
                        int insert = merchantAmtBillMapper.insert(tbMerchantAmtBillPo);
                        if (insert == 0) {
                            log.error("消费提现打款消息，添加商户资金流水失败，id：{}", id);
                            Throw.isBusinessException("审核失败");
                        }

                        // 退回商户本金
                        MerchantAmtAddDto merchantAmtAddDto = new MerchantAmtAddDto();
                        merchantAmtAddDto.setId(withdrawalUserId);
                        merchantAmtAddDto.setBalanceAmt(tradeAmt);
                        Boolean merchantAmtAddState = merchantMapper.merchantAmtAddDto(merchantAmtAddDto);
                        if (merchantAmtAddState == null || !merchantAmtAddState) {
                            log.error("消费提现打款消息，退回商户本金失败，id：{}", id);
                            Throw.isBusinessException("审核失败");
                        }
                    } else if (WithdrawalTypeEnum.MERCHANT_SUBSIDY.getValue().equals(withdrawalType)) {
                        // 增加商户补贴账户资金明细记录
                        TbMerchantAmtBillPo tbMerchantAmtBillPo = new TbMerchantAmtBillPo();
                        tbMerchantAmtBillPo.setBillNo(NoUtils.getMerchantAmtBillNo());
                        tbMerchantAmtBillPo.setMerchantId(tbWithdrawalBillPo.getWithdrawalUserId());
                        tbMerchantAmtBillPo.setBillType(BillTypeEnum.INCOME.getValue());
                        tbMerchantAmtBillPo.setTradeType(MemberAmtBillTradeTypeEnum.WITHDRAWAL_SUBSIDY_FAIL.getValue());
                        tbMerchantAmtBillPo.setRelationTradeNo(tbWithdrawalBillPo.getApplyNo());
                        tbMerchantAmtBillPo.setBeforeAmt(beforeAmt);
                        tbMerchantAmtBillPo.setTradeAmt(tradeAmt);
                        tbMerchantAmtBillPo.setAfterAmt(beforeAmt.add(tradeAmt));
                        tbMerchantAmtBillPo.setRemark(tbWithdrawalBillPo.getRemark());
                        tbMerchantAmtBillPo.setTradeTime(tbWithdrawalBillPo.getApplyTime());
                        tbMerchantAmtBillPo.setCreateTime(LocalDateTime.now());
                        tbMerchantAmtBillPo.setUpdateTime(LocalDateTime.now());
                        int insert = merchantAmtBillMapper.insert(tbMerchantAmtBillPo);
                        if (insert == 0) {
                            log.error("消费提现打款消息，添加商户资金流水失败，id：{}", id);
                            Throw.isBusinessException("审核失败");
                        }

                        // 退回商户补贴
                        MerchantAmtAddDto merchantAmtAddDto = new MerchantAmtAddDto();
                        merchantAmtAddDto.setId(withdrawalUserId);
                        merchantAmtAddDto.setSubsidyAmt(tradeAmt);
                        Boolean merchantAmtAddState = merchantMapper.merchantAmtAddDto(merchantAmtAddDto);
                        if (merchantAmtAddState == null || !merchantAmtAddState) {
                            log.error("消费提现打款消息，退回商户补贴失败，id：{}", id);
                            Throw.isBusinessException("审核失败");
                        }
                    } else if (WithdrawalTypeEnum.AGENT_COMMISSION.getValue().equals(withdrawalType)) {
                        // 增加佣金账户资金明细记录
                        TbCommissionBillPo tbCommissionBillPo = new TbCommissionBillPo();
                        tbCommissionBillPo.setBillNo(NoUtils.getCommissionBillNo());
                        tbCommissionBillPo.setUserId(tbWithdrawalBillPo.getWithdrawalUserId());
                        tbCommissionBillPo.setBillType(BillTypeEnum.INCOME.getValue());
                        tbCommissionBillPo.setTradeType(CommissionBillTradeTypeEnum.WITHDRAWAL_COMMISSION_FAIL.getValue());
                        tbCommissionBillPo.setRelationTradeNo(tbWithdrawalBillPo.getApplyNo());
                        tbCommissionBillPo.setBeforeAmt(beforeAmt);
                        tbCommissionBillPo.setTradeAmt(tradeAmt);
                        tbCommissionBillPo.setAfterAmt(beforeAmt.add(tradeAmt));
                        tbCommissionBillPo.setTradeTime(tbWithdrawalBillPo.getAuditTime());
                        tbCommissionBillPo.setCreateTime(LocalDateTime.now());
                        tbCommissionBillPo.setUpdateTime(LocalDateTime.now());
                        int insert = commissionBillMapper.insert(tbCommissionBillPo);
                        if (insert == 0) {
                            log.error("消费提现打款消息，添加佣金流水失败，id：{}", id);
                            Throw.isBusinessException("审核失败");
                        }

                        // 退回经纪人佣金
                        Boolean addCommissionAmtState = appUserMapper.addCommissionAmt(withdrawalUserId, tradeAmt);
                        if (addCommissionAmtState == null || !addCommissionAmtState) {
                            log.error("消费提现打款消息，退回经纪人佣金失败，id：{}", id);
                            Throw.isBusinessException("审核失败");
                        }
                    }

                    transactionManager.commit(transaction);
                } catch (Exception e) {
                    //回滚事务
                    transactionManager.rollback(transaction);
                    log.error("<消费提现打款消息>事务异常回滚", e);
                    Throw.isBusinessException(e.getMessage());
                }

                // 发送提现失败系统通知   您申请的%s提现，提现失败，原因：%s
                NotifyMsgSendDto notifyMsgSendDto = new NotifyMsgSendDto();
                notifyMsgSendDto.setUserId(tbWithdrawalBillPo.getWithdrawalUserId());
                notifyMsgSendDto.setMsgState(NotifyMsgStateEnum.NO_READ.getValue());
                if (WithdrawalTypeEnum.AGENT_COMMISSION.getValue().equals(tbWithdrawalBillPo.getWithdrawalType())) {
//                    notifyMsgSendDto.setRoleType(RoleTypeEnum.BUSINESS.getValue());
//                    notifyMsgSendDto.setMsgType(NotifyMsgTypeEnum.AGENT_WITHDRAWAL_AUDIT.getValue());
//                    notifyMsgSendDto.setContent(String.format(MsgConstant.AGENT_WITHDRAWAL_AUDIT_SUCCESS,
//                            tbWithdrawalBillPo.getTradeAmt(),
//                            tbWithdrawalBillPo.getApplyNo()));
                } else if (WithdrawalTypeEnum.MERCHANT_SUBSIDY.getValue().equals(tbWithdrawalBillPo.getWithdrawalType())) {
                    // 发送提现失败系统通知
                    notifyMsgSendDto.setRoleType(RoleTypeEnum.MERCHANT.getValue());
                    notifyMsgSendDto.setMsgType(NotifyMsgTypeEnum.MERCHANT_WITHDRAWAL_FAIL.getValue());
                    // 需要判断调用hf提现接口返回的错误, 如果是商户补贴提现, 余额不足,则提示 余额策划人【%s】账户余额不足。
                    notifyMsgSendDto.setContent(String.format(MsgConstant.MERCHANT_WITHDRAWAL_FAIL, tbWithdrawalBillPo.getTradeAmt().toString(), failReason));
                }

                notifyMsgProvider.sendMsg(notifyMsgSendDto);
            } else if ("P".equals(transStat)) {
                // 处理中
                tbWithdrawalBillPo.setState(WithdrawalStateEnum.WITHDRAWAL_PROGRESS.getValue());
//                tbWithdrawalBillPo.setArriveTime(LocalDateTime.now());
                int update = baseMapper.updateById(tbWithdrawalBillPo);
                if (update == 0) {
                    log.error("消费提现打款消息,更新提现状态失败，id：{}", id);
                    Throw.isBusinessException("更新提现状态失败");
                }
            }
        }

        return true;
    }

    @Override
    public List<WithdrawalBillVo> listByDto(WithdrawalBillDto withdrawalBillDto) {
        return baseMapper.listByDto(withdrawalBillDto);
    }

    @Override
    public Boolean scanWithdrawalBill() {
        // 查询提现中的提现记录列表
        List<TbWithdrawalBillPo> tbWithdrawalBillPos = baseMapper.selectList(new QueryWrapper<TbWithdrawalBillPo>().eq("del_state", 0)
                .in("state", Arrays.asList(WithdrawalStateEnum.WITHDRAWAL_PROGRESS.getValue(), WithdrawalStateEnum.AUDIT_SUCCESS.getValue())));
        if (CollectionUtils.isEmpty(tbWithdrawalBillPos)) {
            return true;
        }

        for (TbWithdrawalBillPo tbWithdrawalBillPo : tbWithdrawalBillPos) {
            Long id = tbWithdrawalBillPo.getId();
            Integer withdrawalType = tbWithdrawalBillPo.getWithdrawalType();
            Long withdrawalUserId = tbWithdrawalBillPo.getWithdrawalUserId();
            BigDecimal tradeAmt = tbWithdrawalBillPo.getTradeAmt();

            String hfId = tbWithdrawalBillPo.getHfId();
            String reqSeqId = tbWithdrawalBillPo.getReqSeqId();
            String reqDate = tbWithdrawalBillPo.getReqDate();
            if (StringUtils.isBlank(hfId) || StringUtils.isBlank(reqSeqId) || StringUtils.isBlank(reqDate)) {
                log.error("扫描提现中的提现记录失败,hfId或reqSeqId或reqDate为空, id:{}", id);
                continue;
            }

            HfSettlement hfSettlement = new HfSettlement();
            hfSettlement.setHfId(hfId);
            hfSettlement.setOrgReqDate(reqDate);
            hfSettlement.setOrgReqSeqId(reqSeqId);
            JSONObject jsonObject = hfApi.settlementQuery(hfSettlement).unpack();
            if (jsonObject == null) {
                log.error("扫描提现中的提现记录失败,调用hf出金交易查询失败, id:{}", id);
                continue;
            }

            JSONObject dataJSONObject = jsonObject.getJSONObject("data");
            // 交易状态 S：成功；F：失败；P：处理中；示例值：S
            String transStatus = dataJSONObject.getString("trans_status");
            if ("S".equals(transStatus)) {
                // 提现交易成功,修改提现记录状态,发送系统通知
                TransactionStatus transaction = transactionManager.getTransaction(new DefaultTransactionAttribute());
                try {
                    tbWithdrawalBillPo.setState(WithdrawalStateEnum.WITHDRAWAL_SUCCESS.getValue());
                    tbWithdrawalBillPo.setArriveTime(LocalDateTime.now());
                    int update = baseMapper.updateById(tbWithdrawalBillPo);
                    if (update == 0) {
                        Throw.isBusinessException("更新提现状态失败");
                    }

                    // 如果是自动提现，需要进行状态回写
                    if (WithdrawalTypeEnum.MERCHANT_AUTO_AMT.getValue().equals(tbWithdrawalBillPo.getWithdrawalType())) {
                        autoWithdrawalResultService.onSuccess(tbWithdrawalBillPo.getId());
                    }
                    transactionManager.commit(transaction);
                } catch (Exception e) {
                    //回滚事务
                    transactionManager.rollback(transaction);
                    log.error("<扫描提现中提现记录>事务异常回滚", e);
                    Throw.isBusinessException(e.getMessage());
                }

                // 发送提现到账系统通知
                NotifyMsgSendDto notifyMsgSendDto = new NotifyMsgSendDto();
                notifyMsgSendDto.setUserId(tbWithdrawalBillPo.getWithdrawalUserId());
                notifyMsgSendDto.setRoleType(WithdrawalTypeEnum.AGENT_COMMISSION.getValue().equals(withdrawalType)
                        ? RoleTypeEnum.BUSINESS.getValue()
                        : RoleTypeEnum.MERCHANT.getValue());
                notifyMsgSendDto.setMsgType(NotifyMsgTypeEnum.MERCHANT_WITHDRAWAL_SUCCESS.getValue());
                notifyMsgSendDto.setContent(String.format(MsgConstant.MERCHANT_WITHDRAWAL_SUCCESS, tbWithdrawalBillPo.getTradeAmt().toString()));
                notifyMsgSendDto.setMsgState(NotifyMsgStateEnum.NO_READ.getValue());
                notifyMsgProvider.sendMsg(notifyMsgSendDto);
            } else if ("F".equals(transStatus)) {
                // 提现交易失败,修改提现记录状态,退还提现金额,增加资金流水,发送系统通知

                // 如果是商户补贴提现,需要查询待支付/支付失败的商户补贴类型的订单结算支付流水记录, 返回第一个商家名称作为提现失败原因
                // 如果不存在,表示可能是其他原因,则提现失败原因=提现失败,请联系客服
                String failReason = "提现失败,请联系客服";
                if (WithdrawalTypeEnum.MERCHANT_SUBSIDY.getValue().equals(withdrawalType)) {
                    OrderSettleBillDto orderSettleBillDto = new OrderSettleBillDto();
                    orderSettleBillDto.setTradeType(OrderSettleBillTradeTypeEnum.SUBSIDY_AMT.getValue());
                    orderSettleBillDto.setMerchantId(tbWithdrawalBillPo.getWithdrawalUserId());
                    orderSettleBillDto.setTradeStates(Arrays.asList(OrderSettleBillTradeStateEnum.FAIL.getValue(), OrderSettleBillTradeStateEnum.WAIT.getValue()));
                    List<OrderSettleBillVo> orderSettleBillVos = orderSettleBillApi.listByDto(orderSettleBillDto).unpack();
                    if (!CollectionUtils.isEmpty(orderSettleBillVos)) {
                        OrderSettleBillVo orderSettleBillVo = orderSettleBillVos.get(0);
                        TbBusinessPo businessPo = businessMapper.selectById(orderSettleBillVo.getBusinessId());
                        failReason = String.format("策划人【%s】账户余额不足", businessPo.getBusinessShortName());
                    }
                }

                // 根据提现类型,获取对应的账户余额
                BigDecimal beforeAmt = getBeforeAmt(tbWithdrawalBillPo, withdrawalUserId);

                TransactionStatus transaction = transactionManager.getTransaction(new DefaultTransactionAttribute());

                try {
                    tbWithdrawalBillPo.setState(WithdrawalStateEnum.WITHDRAWAL_FAIL.getValue());
                    tbWithdrawalBillPo.setUpdateTime(LocalDateTime.now());
                    tbWithdrawalBillPo.setHfFailReason(JSON.toJSONString(dataJSONObject));
                    int update = baseMapper.updateById(tbWithdrawalBillPo);
                    if (update == 0) {
                        log.error("扫描提现中的提现记录失败，更新提现状态失败，id：{}", id);
                        Throw.isBusinessException("更新提现状态失败");
                    }

                    // 如果是自动提现，需要进行状态回写
                    if (WithdrawalTypeEnum.MERCHANT_AUTO_AMT.getValue().equals(tbWithdrawalBillPo.getWithdrawalType())) {
                        autoWithdrawalResultService.onFailure(tbWithdrawalBillPo.getId());
                    }

                    if (WithdrawalTypeEnum.MERCHANT_AMT.getValue().equals(withdrawalType)
                            || WithdrawalTypeEnum.MERCHANT_AUTO_AMT.getValue().equals(withdrawalType)) {
                        // 增加商户本金账户资金明细记录
                        TbMerchantAmtBillPo tbMerchantAmtBillPo = new TbMerchantAmtBillPo();
                        tbMerchantAmtBillPo.setBillNo(NoUtils.getMerchantAmtBillNo());
                        tbMerchantAmtBillPo.setMerchantId(tbWithdrawalBillPo.getWithdrawalUserId());
                        tbMerchantAmtBillPo.setBillType(BillTypeEnum.INCOME.getValue());
                        tbMerchantAmtBillPo.setTradeType(MemberAmtBillTradeTypeEnum.WITHDRAWAL_AMT_FAIL.getValue());
                        tbMerchantAmtBillPo.setRelationTradeNo(tbWithdrawalBillPo.getApplyNo());
                        tbMerchantAmtBillPo.setBeforeAmt(beforeAmt);
                        tbMerchantAmtBillPo.setTradeAmt(tradeAmt);
                        tbMerchantAmtBillPo.setAfterAmt(beforeAmt.add(tradeAmt));
                        tbMerchantAmtBillPo.setRemark(tbWithdrawalBillPo.getRemark());
                        tbMerchantAmtBillPo.setTradeTime(tbWithdrawalBillPo.getApplyTime());
                        tbMerchantAmtBillPo.setCreateTime(LocalDateTime.now());
                        tbMerchantAmtBillPo.setUpdateTime(LocalDateTime.now());
                        int insert = merchantAmtBillMapper.insert(tbMerchantAmtBillPo);
                        if (insert == 0) {
                            log.error("扫描提现中的提现记录失败，添加商户资金流水失败，id：{}", id);
                            Throw.isBusinessException("审核失败");
                        }

                        // 退回商户本金
                        MerchantAmtAddDto merchantAmtAddDto = new MerchantAmtAddDto();
                        merchantAmtAddDto.setId(withdrawalUserId);
                        merchantAmtAddDto.setBalanceAmt(tradeAmt);
                        Boolean merchantAmtAddState = merchantMapper.merchantAmtAddDto(merchantAmtAddDto);
                        if (merchantAmtAddState == null || !merchantAmtAddState) {
                            log.error("扫描提现中的提现记录失败，退回商户本金失败，id：{}", id);
                            Throw.isBusinessException("审核失败");
                        }
                    } else if (WithdrawalTypeEnum.MERCHANT_SUBSIDY.getValue().equals(withdrawalType)) {
                        // 增加商户补贴账户资金明细记录
                        TbMerchantAmtBillPo tbMerchantAmtBillPo = new TbMerchantAmtBillPo();
                        tbMerchantAmtBillPo.setBillNo(NoUtils.getMerchantAmtBillNo());
                        tbMerchantAmtBillPo.setMerchantId(tbWithdrawalBillPo.getWithdrawalUserId());
                        tbMerchantAmtBillPo.setBillType(BillTypeEnum.INCOME.getValue());
                        tbMerchantAmtBillPo.setTradeType(MemberAmtBillTradeTypeEnum.WITHDRAWAL_SUBSIDY_FAIL.getValue());
                        tbMerchantAmtBillPo.setRelationTradeNo(tbWithdrawalBillPo.getApplyNo());
                        tbMerchantAmtBillPo.setBeforeAmt(beforeAmt);
                        tbMerchantAmtBillPo.setTradeAmt(tradeAmt);
                        tbMerchantAmtBillPo.setAfterAmt(beforeAmt.add(tradeAmt));
                        tbMerchantAmtBillPo.setRemark(tbWithdrawalBillPo.getRemark());
                        tbMerchantAmtBillPo.setTradeTime(tbWithdrawalBillPo.getApplyTime());
                        tbMerchantAmtBillPo.setCreateTime(LocalDateTime.now());
                        tbMerchantAmtBillPo.setUpdateTime(LocalDateTime.now());
                        int insert = merchantAmtBillMapper.insert(tbMerchantAmtBillPo);
                        if (insert == 0) {
                            log.error("扫描提现中的提现记录失败，添加商户资金流水失败，id：{}", id);
                            Throw.isBusinessException("审核失败");
                        }

                        // 退回商户补贴
                        MerchantAmtAddDto merchantAmtAddDto = new MerchantAmtAddDto();
                        merchantAmtAddDto.setId(withdrawalUserId);
                        merchantAmtAddDto.setSubsidyAmt(tradeAmt);
                        Boolean merchantAmtAddState = merchantMapper.merchantAmtAddDto(merchantAmtAddDto);
                        if (merchantAmtAddState == null || !merchantAmtAddState) {
                            log.error("扫描提现中的提现记录失败，退回商户补贴失败，id：{}", id);
                            Throw.isBusinessException("审核失败");
                        }
                    } else if (WithdrawalTypeEnum.AGENT_COMMISSION.getValue().equals(withdrawalType)) {
                        // 增加佣金账户资金明细记录
                        TbCommissionBillPo tbCommissionBillPo = new TbCommissionBillPo();
                        tbCommissionBillPo.setBillNo(NoUtils.getCommissionBillNo());
                        tbCommissionBillPo.setUserId(tbWithdrawalBillPo.getWithdrawalUserId());
                        tbCommissionBillPo.setBillType(BillTypeEnum.INCOME.getValue());
                        tbCommissionBillPo.setTradeType(CommissionBillTradeTypeEnum.WITHDRAWAL_COMMISSION_FAIL.getValue());
                        tbCommissionBillPo.setRelationTradeNo(tbWithdrawalBillPo.getApplyNo());
                        tbCommissionBillPo.setBeforeAmt(beforeAmt);
                        tbCommissionBillPo.setTradeAmt(tradeAmt);
                        tbCommissionBillPo.setAfterAmt(beforeAmt.add(tradeAmt));
                        tbCommissionBillPo.setTradeTime(tbWithdrawalBillPo.getAuditTime());
                        tbCommissionBillPo.setCreateTime(LocalDateTime.now());
                        tbCommissionBillPo.setUpdateTime(LocalDateTime.now());
                        int insert = commissionBillMapper.insert(tbCommissionBillPo);
                        if (insert == 0) {
                            log.error("扫描提现中的提现记录失败，添加佣金流水失败，id：{}", id);
                            Throw.isBusinessException("审核失败");
                        }

                        // 退回经纪人佣金
                        Boolean addCommissionAmtState = appUserMapper.addCommissionAmt(withdrawalUserId, tradeAmt);
                        if (addCommissionAmtState == null || !addCommissionAmtState) {
                            log.error("扫描提现中的提现记录失败，退回经纪人佣金失败，id：{}", id);
                            Throw.isBusinessException("审核失败");
                        }
                    }

                    transactionManager.commit(transaction);
                } catch (Exception e) {
                    //回滚事务
                    transactionManager.rollback(transaction);
                    log.error("<扫描提现中提现记录>事务异常回滚", e);
                    Throw.isBusinessException(e.getMessage());
                }

                // 发送提现失败系统通知
                NotifyMsgSendDto notifyMsgSendDto = new NotifyMsgSendDto();
                notifyMsgSendDto.setUserId(tbWithdrawalBillPo.getWithdrawalUserId());
                notifyMsgSendDto.setRoleType(WithdrawalTypeEnum.AGENT_COMMISSION.getValue().equals(withdrawalType)
                        ? RoleTypeEnum.BUSINESS.getValue()
                        : RoleTypeEnum.MERCHANT.getValue());
                notifyMsgSendDto.setMsgType(NotifyMsgTypeEnum.MERCHANT_WITHDRAWAL_FAIL.getValue());
                // 需要判断调用hf提现接口返回的错误, 如果是商户补贴提现, 余额不足,则提示 余额策划人【%s】账户余额不足。
                notifyMsgSendDto.setContent(String.format(MsgConstant.MERCHANT_WITHDRAWAL_FAIL, tbWithdrawalBillPo.getTradeAmt().toString(), failReason));
                notifyMsgSendDto.setMsgState(NotifyMsgStateEnum.NO_READ.getValue());
                notifyMsgProvider.sendMsg(notifyMsgSendDto);
            } else if ("P".equals(transStatus)) {
                // 处理中
                tbWithdrawalBillPo.setState(WithdrawalStateEnum.WITHDRAWAL_PROGRESS.getValue());
//                tbWithdrawalBillPo.setArriveTime(LocalDateTime.now());
                int update = baseMapper.updateById(tbWithdrawalBillPo);
                if (update == 0) {
                    log.error("消费提现打款消息,更新提现状态失败，id：{}", id);
                    Throw.isBusinessException("更新提现状态失败");
                }
            }
        }

        return true;
    }

    private BigDecimal getBeforeAmt(TbWithdrawalBillPo tbWithdrawalBillPo, Long withdrawalUserId) {
        BigDecimal beforeAmt = BigDecimal.ZERO;
        if (WithdrawalTypeEnum.MERCHANT_AMT.getValue().equals(tbWithdrawalBillPo.getWithdrawalType())) {
            TbMerchantPo tbMerchantPo = merchantMapper.selectById(withdrawalUserId);
            beforeAmt = tbMerchantPo.getBalanceAmt();
        } else if (WithdrawalTypeEnum.MERCHANT_SUBSIDY.getValue().equals(tbWithdrawalBillPo.getWithdrawalType())) {
            TbMerchantPo tbMerchantPo = merchantMapper.selectById(withdrawalUserId);
            beforeAmt = tbMerchantPo.getSubsidyAmt();
        } else if (WithdrawalTypeEnum.AGENT_COMMISSION.getValue().equals(tbWithdrawalBillPo.getWithdrawalType())) {
            TbAppUserPo tbAppUserPo = appUserMapper.selectById(withdrawalUserId);
            beforeAmt = tbAppUserPo.getCommissionAmt();
        }
        return beforeAmt;
    }

    @Override
    public SubsidyNoEnoughVo getSubsidyNoEnough(Long merchantId) {
        SubsidyNoEnoughVo subsidyNoEnoughVo = new SubsidyNoEnoughVo();

        // 查询商户补贴数据
        OrderSettleBillDto orderSettleBillDto = new OrderSettleBillDto();
        orderSettleBillDto.setMerchantId(merchantId);
        orderSettleBillDto.setTradeType(OrderSettleBillTradeTypeEnum.SUBSIDY_AMT.getValue());
        orderSettleBillDto.setTradeStates(Arrays.asList(OrderSettleBillTradeStateEnum.FAIL.getValue(), OrderSettleBillTradeStateEnum.WAIT.getValue()));
        List<OrderSettleBillVo> orderSettleBillVos = orderSettleBillApi.listByDto(orderSettleBillDto).unpack();
        if (!CollectionUtils.isEmpty(orderSettleBillVos)) {
            Map<Long, List<OrderSettleBillVo>> orderSettleBillVoMap = orderSettleBillVos.stream()
                    .collect(Collectors.groupingBy(OrderSettleBillVo::getBusinessId));

            Map<Long, TbBusinessPo> businessMap = new HashMap<>();
            List<TbBusinessPo> businessPos = businessMapper.selectList(new QueryWrapper<TbBusinessPo>()
                    .in("id", new ArrayList<>(orderSettleBillVoMap.keySet())));
            if (!CollectionUtils.isEmpty(businessPos)) {
                businessMap = businessPos.stream().collect(Collectors.toMap(TbBusinessPo::getId, Function.identity(), (k1, k2) -> k2));
            }

            List<SubsidyNoEnoughPageVo> subsidyNoEnoughPageVos = new ArrayList<>();
            BigDecimal totalNoEnoughAmt = BigDecimal.ZERO;

            for (Long businessId : orderSettleBillVoMap.keySet()) {
                List<OrderSettleBillVo> orderSettleBillVoList = orderSettleBillVoMap.get(businessId);
                if (CollectionUtils.isEmpty(orderSettleBillVoList)) {
                    continue;
                }

                BigDecimal totalTradeAmt = BigDecimal.ZERO;
                for (OrderSettleBillVo orderSettleBillVo : orderSettleBillVoList) {
                    totalTradeAmt = totalTradeAmt.add(orderSettleBillVo.getTradeAmt());
                    totalNoEnoughAmt = totalNoEnoughAmt.add(orderSettleBillVo.getTradeAmt());
                }

                SubsidyNoEnoughPageVo subsidyNoEnoughPageVo = new SubsidyNoEnoughPageVo();
                subsidyNoEnoughPageVo.setWaitWithdrawalAmt(totalTradeAmt);
                TbBusinessPo businessPo = businessMap.get(businessId);
                if (businessPo != null) {
                    subsidyNoEnoughPageVo.setBusinessName(businessPo.getBusinessShortName());
                    subsidyNoEnoughPageVo.setBusinessShortName(businessPo.getBusinessShortName());
                }

                subsidyNoEnoughPageVos.add(subsidyNoEnoughPageVo);
            }

            subsidyNoEnoughVo.setTotalNoEnoughAmt(totalNoEnoughAmt);
            subsidyNoEnoughVo.setSubsidyNoEnoughs(subsidyNoEnoughPageVos);
        }

        return subsidyNoEnoughVo;
    }

    /**
     * 商户已提现商户本金累计
     *
     * @param merchantId 商户id
     * @return 已提现金额
     */
    @Override
    public BigDecimal getMerchantAccWithdrawalAmt(Long merchantId) {
        List<Integer> types = Arrays.asList(WithdrawalTypeEnum.MERCHANT_AMT.getValue(), WithdrawalTypeEnum.MERCHANT_AUTO_AMT.getValue());
        BigDecimal accAmt = baseMapper.sumMerchantWithdrawalAmt(merchantId, types);
        return Optional.ofNullable(accAmt).orElse(BigDecimal.ZERO);
    }

    @Transactional
    @Override
    public Boolean checkBillConfirm(Long checkBillId) {
        WithdrawalCheckBillVo detail = withdrawalCheckBillService.getDetail(checkBillId);
        // 更新提现记录
        TbWithdrawalBillPo withdrawalBillPo = baseMapper.selectById(detail.getWithdrawalBillId());
        withdrawalBillPo.setState(WithdrawalStateEnum.MERCHANT_CONFIRMED.getValue());
        withdrawalBillPo.setUpdateTime(LocalDateTime.now());
        int updateWithdrawalRes = baseMapper.updateById(withdrawalBillPo);
        if (updateWithdrawalRes != 1) {
            Throw.isBusinessException("更新提现记录单失败");
        }
        // 更新核算单
        Boolean res = withdrawalCheckBillService.confirm(checkBillId);
        if (!res) {
            Throw.isBusinessException("更新核算单失败");
        }

        return true;
    }

    /**
     * 结算池提现申请 - 打款 - 上传打款凭证
     */
    @Override
    public Boolean uploadPaymentVoucher(AdminWithdrawalBillPaymentVoucherDto adminWithdrawalBillPaymentVoucherDto) {
        String paymentNo = adminWithdrawalBillPaymentVoucherDto.getPaymentNo();
//        BigDecimal tradeAmt = adminWithdrawalBillPaymentVoucherDto.getTradeAmt();
        String paymentImage = adminWithdrawalBillPaymentVoucherDto.getPaymentImage();
        if (paymentNo == null || paymentNo.isEmpty()) {
            Throw.isBusinessException("请输入打款单号");
        }
//        if (tradeAmt == null || tradeAmt.compareTo(BigDecimal.valueOf(0)) <= 0) {
//            Throw.isBusinessException("请输入打款金额");
//        }
        if (paymentImage == null || paymentImage.isEmpty()) {
            Throw.isBusinessException("请上传打款凭证");
        }
        // 打款单号唯一校验
        TbWithdrawalBillPaymentVoucherPo checkExists = withdrawalBillPaymentVoucherService.getByDto(adminWithdrawalBillPaymentVoucherDto);
        if (checkExists != null) {
            Throw.isBusinessException("打款单号已经存在");
        }

        TbWithdrawalBillPo withdrawalBillPo = baseMapper.selectById(adminWithdrawalBillPaymentVoucherDto.getWithdrawalBillId());
        if (withdrawalBillPo == null) {
            Throw.isBusinessException("提现记录不存在");
        }

        if (!withdrawalBillPo.getMerchantFinancialAccountType().equals(FinancialAccountTypeEnum.PLATFORM.getValue())) {
            Throw.isBusinessException("结算池商户的提现申请才能上传打款凭证");
        }

        if (!withdrawalBillPo.getState().equals(WithdrawalStateEnum.MERCHANT_CONFIRMED.getValue())) {
            Throw.isBusinessException("商户确认后才能上传打款凭证");
        }

        TransactionStatus transaction = transactionManager.getTransaction(new DefaultTransactionAttribute());
        try {
            // 插入打款凭证记录
            boolean success = withdrawalBillPaymentVoucherService.saveByDto(adminWithdrawalBillPaymentVoucherDto);
            if (!success) {
                Throw.isBusinessException("打款凭证保存失败");
            }

            // 提现记录改成已打款(提现成功)
            withdrawalBillPo.setState(WithdrawalStateEnum.WITHDRAWAL_SUCCESS.getValue());
            withdrawalBillPo.setArriveTime(LocalDateTime.now());
            withdrawalBillPo.setUpdateTime(LocalDateTime.now());
            int update = baseMapper.updateById(withdrawalBillPo);
            if (update <= 0) {
                log.error("上传打款凭证 - 更新提现记录状态失败，id：{}", withdrawalBillPo.getId());
                Throw.isBusinessException("打款凭证保存失败。");
            }

            transactionManager.commit(transaction);
        } catch (Exception e) {
            transactionManager.rollback(transaction);
            log.error("<提现打款>事务异常回滚", e);
            Throw.isBusinessException(e.getMessage());
        }

        return true;
    }


    @Override
    public WithdrawalCheckBillInitVo initCheck(Long withdrawalId) {
        TbWithdrawalBillPo withdrawalBillPo = getById(withdrawalId);
        if (WithdrawalStateEnum.WAIT_AUDIT.getValue() != withdrawalBillPo.getState()) {
            Throw.isBusinessException("待审核的提现记录才能生成核算单");
        }
        return withdrawalCheckBillService.initializeCheckBill(withdrawalBillPo);
    }

    @Override
    public WithdrawalCheckBillInitVo checkInfo(Long checkBillId) {
        return withdrawalCheckBillService.checkInfo(checkBillId);
    }

    @Transactional
    @Override
    public Boolean saveCheckBill(WithdrawalCheckBillSaveDto checkBillSaveDto) {
        WithdrawalCheckBillVo checkBill = withdrawalCheckBillService.getDetail(checkBillSaveDto.getCheckBillId());
        if (checkBill.getStatus() == 2) {
            Throw.isBusinessException("商户已确认，无法修改");
        }
        CheckBillSaveResultVo checkBillSaveResultVo = withdrawalCheckBillService.saveCheckBill(checkBillSaveDto);

        TbWithdrawalBillPo withdrawalBillPo = baseMapper.selectById(checkBill.getWithdrawalBillId());
        withdrawalBillPo.setState(WithdrawalStateEnum.WAIT_MERCHANT_CONFIRM.getValue());
        withdrawalBillPo.setUpdateTime(LocalDateTime.now());
        withdrawalBillPo.setFeeAmt(checkBillSaveResultVo.getFeeAmt());
        withdrawalBillPo.setCheckDeductAmt(checkBillSaveResultVo.getCheckDeductAmt());
        BigDecimal receiveAmt = withdrawalBillPo.getTradeAmt()
                .subtract(withdrawalBillPo.getFeeAmt())
                .subtract(withdrawalBillPo.getCheckDeductAmt());
        withdrawalBillPo.setReceiveAmt(receiveAmt);
        updateById(withdrawalBillPo);
        return true;
    }

    @Override
    public TbWithdrawalBillPaymentVoucherVo getPaymentVoucher(Long withdrawalBillId) {
        AdminWithdrawalBillPaymentVoucherDto dto = new AdminWithdrawalBillPaymentVoucherDto();
        dto.setWithdrawalBillId(withdrawalBillId);
        TbWithdrawalBillPaymentVoucherPo po = withdrawalBillPaymentVoucherService.getByDto(dto);

        TbWithdrawalBillPaymentVoucherVo vo = new TbWithdrawalBillPaymentVoucherVo();
        if (po != null) {
            BeanUtils.copyProperties(po, vo);
        }

        return vo;
    }

}
